// graphql_config.dart
import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:http/io_client.dart';
import 'package:labcloud_app/api/service/auth_service.dart';
import 'dart:io';
import 'package:http/http.dart' as http show Client; // 引入 http 包

// 添加 Web 兼容的导入
import 'package:http/browser_client.dart' if (dart.library.io) 'package:http/io_client.dart';


import '../config/token_refresh_queue.dart';
import '../config/token_storage.dart';


class GraphQLConfig {
  static final String _baseUrl = 'https://wujianming.xyz/api/graphql';

  // static HttpLink httpLink = HttpLink(
  //   _baseUrl,
  //   httpClient: _createHttpClient(),
  // );


  static http.Client createClient() {
    if (kIsWeb) {
      // Web 平台使用 BrowserClient
      return BrowserClient();
    } else {
      // 原生平台使用 IOClient 包装 HttpClient
      final httpClient = HttpClient()
        ..badCertificateCallback = (X509Certificate cert, String host, int port) {
          // 在开发环境中，可以接受所有证书
          // 生产环境中应该进行更严格的验证
          return kDebugMode;
        };
      return IOClient(httpClient);
    }
  }

  // 将 httpLink 改为静态 getter
  static Link get httpLink {
    return HttpLink(_baseUrl, httpClient: createClient());
  }


  // 响应拦截Link
// 替换原有的 authLink 实现
  static Link authLink = Link.function((request, [forward]) async* {
    // 1. 获取当前 access token
    final String? accessToken = await TokenStorage.getAccessToken();
    final String? refreshToken = await TokenStorage.getRefreshToken();
    Request req = request;
    print('accessToken: $accessToken');
    if (kDebugMode) {
      print('accessToken: $accessToken');
      print('refreshToken: $refreshToken');
    }
    if (accessToken != null && accessToken.isNotEmpty) {
      // 2. 将 token 注入请求头
      req = request.updateContextEntry<HttpLinkHeaders>(
            (HttpLinkHeaders? headers) => HttpLinkHeaders(
          headers: <String, String>{
            ...headers?.headers ?? {},
            'Authorization': 'Bearer $accessToken',
          },
        ),
      );
    }

    final Stream<Response> responseStream = forward!(req);

    await for (final response in responseStream) {
      // 3. 检查是否为 Token 过期错误
      if (_isTokenExpired(response) && refreshToken != null && refreshToken.isNotEmpty) {

        // 4. 通过队列发起 Token 刷新
        final newToken = await TokenRefreshQueue.instance.queueTokenRefresh(
              () => AuthService.refreshToken(
            GraphQLClient(
              link: httpLink,
              cache: GraphQLCache(),
            ),
          ),
        );

        // 5. 使用新 token 更新请求头并重新发起请求
        req = req.updateContextEntry<HttpLinkHeaders>(
              (HttpLinkHeaders? headers) => HttpLinkHeaders(
            headers: <String, String>{
              ...headers?.headers ?? {},
              'Authorization': 'Bearer $newToken',
            },
          ),
        );

        // 重新发送请求并 yield 新的结果
        await for (final newResponse in forward(req)) {
          yield newResponse;
        }
      } else {
        // 正常情况直接 yield 响应
        yield response;
      }
    }

  });

  static Link link = authLink.concat(httpLink);



  static ValueNotifier<GraphQLClient> initClient() {
    final client = GraphQLClient(
      cache: GraphQLCache(),
      link: link,
      defaultPolicies: DefaultPolicies(
        query: Policies(fetch: FetchPolicy.networkOnly),      // 查询禁用缓存
        mutate: Policies(fetch: FetchPolicy.networkOnly),     // 变更禁用缓存
        subscribe: Policies(fetch: FetchPolicy.networkOnly),  // 订阅禁用缓存
      ),
    );

    return ValueNotifier(client);
  }

  // 处理证书免校验
  static IOClient _createHttpClient() {
    if (kDebugMode) {
      HttpClient httpClient = HttpClient()
        ..badCertificateCallback = (X509Certificate cert, String host,
            int port) {
          return true;
        };
      return IOClient(httpClient);
    }
    return IOClient();
  }

  static bool _isTokenExpired(Response response) {
    // 判断是否为 Token 过期错误，可根据实际后端错误格式调整
    final errors = response.errors;
    if (errors != null) {
      for (var error in errors) {
        if (error.extensions != null && error.extensions!['code'] == 'UNAUTHORIZED') {
          return true;
        }
      }
    }
    return false;
  }
}
